package com.vvv.shortlink.project.mq.consumer;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vvv.shortlink.project.annotation.MQIdempotent;
import com.vvv.shortlink.project.constant.RocketMqConstant;
import com.vvv.shortlink.project.dao.entity.*;
import com.vvv.shortlink.project.dao.mapper.*;
import com.vvv.shortlink.project.dto.biz.LinkStatsRecordDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.vvv.shortlink.common.toolkit.LinkUtil.AMAP_URL;


/**
 * @author vvv
 * @date 2024/2/28 16 25
 * discription
 */
@Slf4j
@Component
@RefreshScope
@RequiredArgsConstructor
@RocketMQMessageListener(
        topic = RocketMqConstant.LINK_STATS_TOPIC,
        selectorExpression = RocketMqConstant.LINK_STATS_SAVE_TAG,
        consumerGroup = RocketMqConstant.LINK_STATS_GROUP
)
public class LinkStatsSaveConsumer implements RocketMQListener<LinkStatsRecordDTO> {

    private final LinkGotoMapper linkGotoMapper;
    private final LinkAccessStatsMapper linkAccessStatsMapper;
    private final LinkLocaleStatsMapper linkLocaleStatsMapper;
    private final LinkOsStatsMapper linkOsStatsMapper;
    private final LinkBrowserStatsMapper linkBrowserStatsMapper;
    private final LinkAccessLogsMapper linkAccessLogsMapper;
    private final LinkDeviceStatsMapper linkDeviceStatsMapper;
    private final LinkNetworkStatsMapper linkNetworkStatsMapper;

    @Value("${short-link.stats.local.amap-key}")
    private String amapKey;

    /**
     * 一键切换 mysql流水表和 redis setnx 处理幂等逻辑
     * @param shortLinkStatsRecordDTO
     */
    @Override
    @MQIdempotent
    public void onMessage(LinkStatsRecordDTO shortLinkStatsRecordDTO) {
        String fullShortUrl = shortLinkStatsRecordDTO.getFullShortUrl();
        Long userId = shortLinkStatsRecordDTO.getUserId();
        String realIp = shortLinkStatsRecordDTO.getIp();
        String os = shortLinkStatsRecordDTO.getOs();
        String browser = shortLinkStatsRecordDTO.getBrowser();
        String device = shortLinkStatsRecordDTO.getDevice();
        String network = shortLinkStatsRecordDTO.getNetwork();
        String uvValue = shortLinkStatsRecordDTO.getUvValue();
        Boolean isFirstUv = shortLinkStatsRecordDTO.getIsFirstUv();
        Boolean isFirstUip = shortLinkStatsRecordDTO.getIsFirstUip();

        // 如果短链跳转走的是缓存的话是拿不到user_id的
        if (userId == null) {
            LambdaQueryWrapper<LinkGotoDO> queryWrapper = Wrappers.lambdaQuery(LinkGotoDO.class)
                    .eq(LinkGotoDO::getFullShortUrl, fullShortUrl);
            LinkGotoDO linkGotoDO = linkGotoMapper.selectOne(queryWrapper);
            userId = linkGotoDO.getUserId();
        }

        try {
            // 基础监控信息
            Date date = new Date();
            int hour = DateUtil.hour(date, true);
            int week = DateUtil.dayOfWeekEnum(date).getIso8601Value();
            LinkAccessStatsDO linkAccessStatsDO = LinkAccessStatsDO.builder()
                    .pv(1)
                    .uv(isFirstUv ? 1 : 0)
                    .uip(isFirstUip ? 1 : 0)
                    .fullShortUrl(fullShortUrl)
                    .userId(userId)
                    .hour(hour)
                    .weekday(week)
                    .date(date)
                    .build();
            linkAccessStatsMapper.monitorShortLink(linkAccessStatsDO);
            // 地区判断
            String local = saveLocalStatsByIp(fullShortUrl, userId, realIp, date);
            // 操作系统判断
            LinkOsStatsDO linkOsStatsDO = LinkOsStatsDO.builder()
                    .fullShortUrl(fullShortUrl)
                    .userId(userId)
                    .date(date)
                    .cnt(1)
                    .os(os)
                    .build();
            linkOsStatsMapper.monitorShortLink(linkOsStatsDO);
            // 浏览器类型判断
            LinkBrowserStatsDO linkBrowserStatsDO = LinkBrowserStatsDO.builder()
                    .browser(browser)
                    .cnt(1)
                    .userId(userId)
                    .fullShortUrl(fullShortUrl)
                    .date(new Date())
                    .build();
            linkBrowserStatsMapper.monitorShortLink(linkBrowserStatsDO);
            // 设备类型判断
            LinkDeviceStatsDO linkDeviceStatsDO = LinkDeviceStatsDO.builder()
                    .device(device)
                    .cnt(1)
                    .userId(userId)
                    .fullShortUrl(fullShortUrl)
                    .date(new Date())
                    .build();
            linkDeviceStatsMapper.monitorShortLink(linkDeviceStatsDO);
            // 网络类型判断
            LinkNetworkStatsDO linkNetworkStatsDO = LinkNetworkStatsDO.builder()
                    .network(network)
                    .cnt(1)
                    .userId(userId)
                    .fullShortUrl(fullShortUrl)
                    .date(new Date())
                    .build();
            linkNetworkStatsMapper.monitorShortLink(linkNetworkStatsDO);
            // 高频ip日志
            LinkAccessLogsDO linkAccessLogsDO = LinkAccessLogsDO.builder()
                    .ip(realIp)
                    .os(os)
                    .browser(browser)
                    .device(device)
                    .network(network)
                    .local(local)
                    .user(uvValue)
                    .fullShortUrl(fullShortUrl)
                    .userId(userId)
                    .build();
            linkAccessLogsMapper.insert(linkAccessLogsDO);
        } catch (Exception e) {
            log.error("短链接: {} 监控错误{}", fullShortUrl, e);
        }
    }

    private String saveLocalStatsByIp(String fullShortUrl, Long userId, String realIp, Date date) {
        // 构建请求参数
        Map<String, Object> requestParamMap = new HashMap<>();
        requestParamMap.put("key", amapKey);
        requestParamMap.put("ip", realIp);
        // 调用高德地图api
        String result = HttpUtil.get(AMAP_URL, requestParamMap);
        // 解析参数
        JSONObject jsonObject = JSONUtil.parseObj(result);
        String infoCode = jsonObject.getStr("infocode");
        String province = "";
        String city = "";
        String adcode;
        final String country = "中国";
        final String defaultValue = "未知";
        LinkLocalStatsDO linkLocalStatsDO = null;
        // 成功
        if (StringUtils.equals(infoCode, "10000")) {
            province = jsonObject.getStr("province");
            city = jsonObject.getStr("city");
            adcode = jsonObject.getStr("adcode");
            province = province.equals("[]") ? defaultValue : province;
            city = city.equals("[]") ? defaultValue : city;
            adcode = adcode.equals("[]") ? defaultValue : adcode;
            linkLocalStatsDO = LinkLocalStatsDO.builder()
                    .fullShortUrl(fullShortUrl)
                    .userId(userId)
                    .date(date)
                    .province(province)
                    .city(city)
                    .adcode(adcode)
                    .country(country)
                    .cnt(1)
                    .build();
        } else {
            // 失败
            linkLocalStatsDO = LinkLocalStatsDO.builder()
                    .fullShortUrl(fullShortUrl)
                    .userId(userId)
                    .date(date)
                    .province(defaultValue)
                    .city(defaultValue)
                    .adcode(defaultValue)
                    .country(country)
                    .cnt(1)
                    .build();
            log.error("高德地图出错");
        }
        linkLocaleStatsMapper.monitorShortLink(linkLocalStatsDO);
        return country + "-" + province + "-" + city;
    }
}
